package com.weic.easycache.widget;

import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.widget.PopupWindow;

public class CenterPopupWindow extends PopupWindow {
	private static final int LOCATION_AT_CENTER = 0;
	private static final int LOCATION_ALIGN_CENTER = 1;
	private static final int LOCATION_DROPDOWN = 2;
	private static final int LOCATION_TOOLTIP = 3;

	private int mLocation, mXoff, mYoff;

	private View mContentView;
	private Rect mBoundary = new Rect();
	private View mAnchor, mBoundaryView;

	public CenterPopupWindow(View contentView, Drawable backgroundDrawable, boolean hideOutsideTouch) {
		super(contentView);
		mContentView = contentView;
		setWindowLayoutMode(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
		if(hideOutsideTouch) {
			//为true则事件会传递到 PopupWindow内部的View，为false则不能拦截事件，但仍然可以点击外面
			setOutsideTouchable(true);
			backgroundDrawable = backgroundDrawable==null ? new ColorDrawable(0x00000000) : backgroundDrawable;
			//setOutsideTouchable(true)，同时必须设置一个背景才能够拦截ACTION_OUTSIDE
			setBackgroundDrawable(backgroundDrawable);
		}else {
			if(backgroundDrawable != null) {
				setBackgroundDrawable(backgroundDrawable);
			}
		}
	}

	public void showAtCenter(View anchor) {
		showAtCenter(anchor, null);
	}

	/**显示在某View的正上方，弹出窗口的原点与anchor的中央对齐
	 * @param anchor		
	 * @param boundaryView	弹出窗口显示的边界为该View的边界。如果为null，则以屏幕为边界
	 **/
	public void showAtCenter(View anchor, View boundaryView) {
		mLocation = LOCATION_AT_CENTER;
		mAnchor = anchor;
		mBoundaryView = boundaryView;
		windowLayout();
	}

	public void showAlignCenter(View anchor) {
		showAlignCenter(anchor, null);
	}

	/**显示在某View的正上方，中央对齐
	 * @param anchor		弹出窗口将显示在anchor的上方正中央
	 * @param boundaryView	弹出窗口显示的边界为该View的边界。如果为null，则以屏幕为边界
	 **/
	public void showAlignCenter(View anchor, View boundaryView) {
		mLocation = LOCATION_ALIGN_CENTER;
		mAnchor = anchor;
		mBoundaryView = boundaryView;
		windowLayout();
	}

	public void showAsDropDown(View anchor) {
		showAsDropDown(anchor, null);
	}

	public void showAsDropDown(View anchor, View boundaryView) {
		showAsDropDown(anchor, boundaryView, 0, 0);
	}

	public void showAsDropDown(View anchor, View boundaryView, int xoff, int yoff) {
		mLocation = LOCATION_DROPDOWN;
		mAnchor = anchor;
		mBoundaryView = boundaryView;
		mXoff = xoff;
		mYoff = yoff;
		windowLayout();
	}

	public void showAsTooltip(View anchor) {
		showAsTooltip(anchor, null, 0, 0);
	}

	public void showAsTooltip(View anchor, View boundaryView) {
		showAsTooltip(anchor, boundaryView, 0, 0);
	}

	/**
	 * 以提示信息的方式来显示
	 * @param anchor
	 * @param xoff	Tooltip的小三角相定点对于anchor原点的x坐标
	 * @param yoff	Tooltip的小三角相定点对于anchor原点的y坐标
	 */
	public void showAsTooltip(View anchor, View boundaryView, int xoff, int yoff) {
		mLocation = LOCATION_TOOLTIP;
		mAnchor = anchor;
		mBoundaryView = boundaryView;
		mXoff = xoff;
		mYoff = yoff;
		windowLayout();
	}

	private void windowLayout() {
		if(mAnchor!=null && mAnchor.getWindowToken()!=null) {
			int rootWidth = mContentView.getWidth();
			int rootHeight = mContentView.getHeight();
			//mWindow.getWidth()的值不会随着测量而改变

			int[] location = new int[2];
			mAnchor.getLocationOnScreen(location);

			if(rootWidth<=0 || rootHeight<=0) {
				mContentView.setVisibility(View.INVISIBLE);
				postReLayout();
				//这里不能return，只有在显示了之后才会进行测量布局
			}else {
				mContentView.setVisibility(View.VISIBLE);

				if(mBoundaryView == null) {
					DisplayMetrics dMs = mContentView.getContext().getResources().getDisplayMetrics();
					mBoundary.left = 0;
					mBoundary.top = 0;
					mBoundary.right = dMs.widthPixels;
					mBoundary.bottom = dMs.heightPixels;
				}else {
					int[] loc = new int[2];
					mBoundaryView.getLocationOnScreen(loc);
					mBoundary.left = loc[0];
					mBoundary.top = loc[1];
					mBoundary.right = mBoundary.left+mBoundaryView.getWidth();
					mBoundary.bottom = mBoundary.top+mBoundaryView.getHeight();
				}
				switch (mLocation) {
				case LOCATION_AT_CENTER:
					location[0] += mAnchor.getWidth()/2;
					location[1] += mAnchor.getHeight()/2;
					location[0] = location[0]<mBoundary.left ? mBoundary.left : location[0]+rootWidth>mBoundary.right ? mBoundary.right-rootWidth : location[0];
					location[1] = location[1]<mBoundary.top ? mBoundary.top : location[1]+rootHeight>mBoundary.bottom ? mBoundary.bottom-rootHeight : location[1];
					break;
				case LOCATION_ALIGN_CENTER:
					location[0] += mAnchor.getWidth()/2 - rootWidth/2;
					location[1] += mAnchor.getHeight()/2 - rootHeight/2;
					location[0] = location[0]<mBoundary.left ? mBoundary.left : location[0]+rootWidth>mBoundary.right ? mBoundary.right-rootWidth : location[0];
					location[1] = location[1]<mBoundary.top ? mBoundary.top : location[1]+rootHeight>mBoundary.bottom ? mBoundary.bottom-rootHeight : location[1];
					break;
				case LOCATION_DROPDOWN:
					location[0] += mXoff;
					location[0] = location[0]<mBoundary.left ? mBoundary.left : location[0]+rootWidth>mBoundary.right ? mBoundary.right-rootWidth : location[0];
					if(location[1]+mAnchor.getHeight()+rootHeight+mYoff > mBoundary.bottom) {
						if(location[1]-rootHeight-mYoff > mBoundary.top) {
							location[1] -= rootHeight+mYoff;
						}else {
							location[1] = mBoundary.bottom-rootHeight;
						}
					}else {
						location[1] += mAnchor.getHeight()+mYoff;
					}
					break;
				case LOCATION_TOOLTIP:
					location[0] += mXoff-rootWidth/2;
					location[0] = location[0]<mBoundary.left ? mBoundary.left : location[0]+rootWidth>mBoundary.right ? mBoundary.right-rootWidth : location[0];
					location[1] += mYoff-rootHeight;
					break;
				}
			}
			if(isShowing()) {
				update(location[0], location[1], -1, -1);
			}else {
				showAtLocation(mAnchor, Gravity.NO_GRAVITY, location[0], location[1]);
			}
		}else {
			dismiss();
		}
	}

	private void postReLayout() {
		/*如果尺寸<=0,肯定会自动测量重绘，这里不需要再补充
		mContentView.requestLayout();
		mContentView.invalidate();*/
		mContentView.removeCallbacks(mReLayout);
		mContentView.post(mReLayout);
	}

	private Runnable mReLayout = new Runnable() {
		@Override
		public void run() {
			windowLayout();
		}
	};

	@Override
	public void dismiss() {
		mContentView.removeCallbacks(mReLayout);
		super.dismiss();
	};
}
